#pragma once
#include <bit>
#include <vector>
#include <string>
#include <concepts>

#include <cstring>

#include "runtime check.hpp"
#include "my_log.hpp"

#ifdef defined(_WIN32) || defined(_WIN64)
    static constexpr inline char byte_order = 'l';
#elif defined(__linux__)
    #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)  
        static constexpr inline char byte_order = 'l'; 
    #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)  
        static constexpr inline char byte_order = 'b';  
    #endif
#endif

class faster_bitmap
{
private:
    class bit_refrence
    {
    public:
        bit_refrence(std::vector<unsigned char>& block_ref, size_t which)
            : _block_ref(block_ref)
            , _which(which)
        {}

    private:
        std::vector<unsigned char>& _block_ref;
        size_t _which;
    };

public:
    faster_bitmap()
        : _size(0)
    {}

    faster_bitmap(std::integral auto input)
        : _size(sizeof(input) * 8 - std::countl_zero(input))
    {
        char* it = reinterpret_cast<char*>(&input);
        if (byte_order == 'l')
        {
            for (size_t i = 0; i < _size; i += 8)
            {
                _block.push_back(*it);
                ++it;
            }
        }
        if (byte_order == 'b')
        {
            for (size_t i = 0; i < _size; i += 8)
            {
                ++it;
            }
            for (size_t i = 0; i < _size; i += 8)
            {
                _block.push_back(*it);
                --it;
            }
        }
    }

    faster_bitmap(const char* input, const std::string& mode)
        : _size(strlen(input))
    {
        fill(input, _size, mode);
    }

    faster_bitmap(const std::string& input, const std::string& mode)
        : _size(input.size())
    {
        fill(input.c_str(), _size, mode);
    }

    faster_bitmap(const faster_bitmap& other)
        : _block(other._block)
        , _size(other._size)
    {}

    faster_bitmap(faster_bitmap&& other)
        : _block(std::move(other._block))
        , _size(other._size)
    {}

    void swap(faster_bitmap& other)
    {
        _block.swap(other._block);
        std::swap(_size, other._size);
    }

    faster_bitmap& operator=(faster_bitmap other)
    {
        swap(other);
        return *this;
    }

    faster_bitmap& operator=(faster_bitmap&& other)
    {
        _block = std::move(other._block);
        _size = other._size;
        return *this;
    }

    bit_refrence operator[](bool index)
    {

    }

    bool operator[](bool index) const
    {
        
    }

    std::vector<size_t> test()
    {

    }

    std::vector<size_t> test()
    {
        
    }

private:
    void fill(const char* input, size_t size, const std::string& mode)
    {
        size_t tem = 0;
        if (mode == "bin")
        {
            bin_to_b(input, size);
        }
        else if (mode == "oct")
        {
            oct_to_b(input, size);
        }
        else if (mode == "hex")
        {
            hex_to_b(input, size);
        }
        else
        {
            lg.basic_print(level::FATAL, std::make_tuple("faster bitset.hpp: invalid initializing mode"), true);
            std::terminate();
        }
    }

    void bin_to_b(const char* input, size_t size)
    {
        size_t tem = 0;
        for (size_t i = 0; i < size; i += 8)
        {
            for (size_t j = 0; j < 8 && i + j < size; ++j)
            {
                runtime_check()((input[i + j] - '0' == 0 || input[i + j] - '0' == 1), "out of range");
                tem |= input[i + j] << (7 - j);
            }
            _block.push_back(tem);
            tem = 0;
        }
    }

    void oct_to_b(const char* input, size_t size)
    {
        size_t tem = 0;
        constexpr const size_t o_to_b[8] = { 0, 1, 10, 11, 100, 101, 110, 111};
        constexpr const size_t o_to_b_len[8] = { 1, 1, 2, 2, 3, 3, 3, 3};
        size_t left_bit = 0;
        size_t left_len = 0;
        bool is_left = false;
        for (size_t i = 0, j = 0; i < size; ++i)
        {
            if (is_left)
            {
                tem |= left_bit << (8 - left_len);
                is_left = false;
                j += left_len;
            }
            runtime_check()((input[i] - '0' >= 0 && input[i] - '0' <= 7), "out of range");
            if (j + o_to_b_len[input[i]] <= 8)
            {
                tem |= o_to_b[input[i]] << (8 - o_to_b_len[input[i]] - j);
                j += o_to_b_len[input[i]];
            }
            else
            {
                is_left = true;
                left_len = j + o_to_b_len[input[i]] - 8;
                tem |= o_to_b[input[i]] >> left_len;
                left_bit = o_to_b[input[i]] << (8 - left_len) >> (8 - left_len);
                j = 8;
            }
            if (j == 8)
            {
                _block.push_back(tem);
                tem = 0;
                j = 0;
            }
        }
    }

    void hex_to_b(const char* input, size_t size)
    {
        size_t tem = 0;
        constexpr const size_t h_to_b_n[10] = { 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001};
        constexpr const size_t h_to_b_l[6] = { 1010, 1011, 1100, 1101, 1110, 1111};
        constexpr const size_t h_to_b_n_len[10] = { 1, 1, 2, 2, 3, 3, 3, 3, 4, 4};
        constexpr const size_t h_to_b_l_len[6] = { 4, 4, 4, 4, 4, 4};
        size_t left_bit = 0;
        size_t left_len = 0;
        bool is_left = false;
        bool is_complete = false;
        const size_t* h_to_b = nullptr;
        const size_t* h_to_b_len = nullptr;
        size_t convert_value = 0;
        for (size_t i = 0, j = 0; i < size; ++i)
        {
            if (is_left)
            {
                tem |= left_bit << (8 - left_len);
                is_left = false;
                j += left_len;
            }
            runtime_check()(((input[i] - '0' >= 0 && input[i] - '0' <= 9) || (input[i] - 'a' >= 0 && input[i] - 'a' <= 5)), "out of range");
            if (input[i] - '0' >= 0 && input[i] - '0' <= 9)
            {
                h_to_b = h_to_b_n;
                h_to_b_len = h_to_b_n_len;
                convert_value = input[i];
            }
            else
            {
                h_to_b = h_to_b_l;
                h_to_b_len = h_to_b_l_len;
                convert_value = input[i] - 'a';
            }
            if (j + h_to_b_len[convert_value] <= 8)
            {
                tem |= h_to_b[convert_value] << (8 - h_to_b_len[convert_value] - j);
                j += h_to_b_len[convert_value];
            }
            else
            {
                is_left = true;
                left_len = j + h_to_b_len[convert_value] - 8;
                tem |= h_to_b[convert_value] >> left_len;
                left_bit = h_to_b[convert_value] << (8 - left_len) >> (8 - left_len);
                j = 8;
            }
            if (j == 8)
            {
                _block.push_back(tem);
                tem = 0;
                j = 0;
            }
        }
    }

    
private:
    std::vector<unsigned char> _block;
    size_t _size;
};